home *** CD-ROM | disk | FTP | other *** search
/ Over 1,000 Windows 95 Programs / Over 1000 Windows 95 Programs (Microforum) (Disc 1).iso / 0362 / bcsdk.zip / CDPLAY.C < prev    next >
C/C++ Source or Header  |  1995-04-01  |  11KB  |  494 lines

  1. /*
  2.     BarClock(tm)
  3.  
  4.     Keyword Extension Sample
  5.  
  6.     Copyright (c) 1994  Patrick Breen
  7.     All rights reserved.
  8.  
  9.     Contact Information:
  10.  
  11.         Atomic Dog Software
  12.         PO Box 523
  13.         Medford, MA 02155
  14.  
  15.         Phone (617) 396-2673
  16.         Fax   (617) 396-5761
  17.  
  18.         Internet:            pbreen@world.std.com
  19.         CompuServe:         70312,743
  20.         America Online:     PBreen
  21. */
  22.  
  23. #include "bchook.h"
  24. #include <mmsystem.h>
  25.  
  26. static BOOL OpenCDDevice(BOOL);
  27. static void CloseCDDevice(void);
  28. static void PlayTrack(DWORD track);
  29. static void PauseCD(void);
  30. static void StopCD(void);
  31. static void GoToTrack(BOOL bNext);
  32. static void CDEject(void);
  33. static void ErrorProc(DWORD);
  34.  
  35.  
  36. // Handle to the DLL instance from Libinit.asm
  37. HANDLE LIBINST;
  38. WORD wGlobalDeviceID = 0;
  39. HMENU hMenu;
  40.  
  41. void cdecl _cexit(void)
  42. {
  43. }
  44.  
  45. // Standard library initialization
  46. int FAR PASCAL LibMain(HINSTANCE hInstance, WORD a, WORD b, LPSTR c)
  47. {
  48.     LIBINST = hInstance;
  49.     return 1;
  50. }
  51.  
  52. // Standard library exit
  53. int FAR PASCAL WEP(int a)
  54. {
  55.     return TRUE;
  56. }
  57.  
  58. // Standard version number return
  59. DWORD FAR _export BCHookVersion(DWORD FAR *pSig)
  60. {
  61.     (*pSig) = 0x03534441L;        // 'ADS' (in reverse) x3
  62.     return HOOKVERSION;
  63. }
  64.  
  65. // Return the number of buttons we support
  66. BYTE FAR _export BCBtnCount(void)
  67. {
  68.     // We support 1 buttons
  69.     return 1;
  70. }
  71.  
  72. // Return the label for the button
  73. void FAR _export BCBtnLabel(BYTE btnId, LPSTR pLabelBuf)
  74. {
  75.     MCI_STATUS_PARMS mcistatus;
  76.     DWORD dwRes;
  77.     DWORD track;
  78.  
  79.     // Copy appropriate label into buffer
  80.     lstrcpy(pLabelBuf, "CD Controls");
  81.  
  82.     if (wGlobalDeviceID) {
  83.  
  84.          // Get current track
  85.         mcistatus.dwItem = MCI_STATUS_CURRENT_TRACK;
  86.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  87.                            (DWORD)(LPSTR)&mcistatus);
  88.         track = (dwRes)? 0:mcistatus.dwReturn;
  89.  
  90.         // Get total tracks
  91.         mcistatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  92.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  93.                            (DWORD)(LPSTR)&mcistatus);
  94.  
  95.         // Tack on to label
  96.         if (track && !dwRes) {
  97.             wsprintf(pLabelBuf + lstrlen(pLabelBuf),
  98.                     " - (Track %d of %d)",
  99.                     (short) track,
  100.                     (short) mcistatus.dwReturn);
  101.         }
  102.     }
  103. }
  104.  
  105. // Return a menu that should be displayed
  106. // when the specified button is clicked -
  107. // this function is called just prior to
  108. // display of the menu
  109. HMENU FAR _export BCBtnMenu(BYTE btnId, BOOL bLeft)
  110. {
  111.     if (!bLeft) {
  112.  
  113.         // Create a popup menu (if a resource
  114.         // menu is used, be sure to call the
  115.         // function GetSubMenu to get the
  116.         // proper popup menu handle to display
  117.         //
  118.         // e.g.
  119.         //
  120.         // hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(id));
  121.         // hPopup = GetSubMenu(hMenu, 0);
  122.  
  123.         // We will create our menu
  124.         hMenu = CreatePopupMenu();
  125.  
  126.         // Add to the menu
  127.         AppendMenu(hMenu, 0, 1, "Play");
  128.         AppendMenu(hMenu, 0, 2, "Pause");
  129.         AppendMenu(hMenu, 0, 3, "Stop");
  130.         AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
  131.         AppendMenu(hMenu, 0, 4, "Next Track");
  132.         AppendMenu(hMenu, 0, 5, "Prev Track");
  133.         AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
  134.         AppendMenu(hMenu, 0, 6, "Eject");
  135.     }
  136.  
  137.     return hMenu;
  138. }
  139.  
  140. // Handle a button select
  141. void FAR _export BCBtnClick(BYTE btnId, BOOL bLeft)
  142. {
  143.     // Toggle pause state
  144.     PauseCD();
  145. }
  146.  
  147. // Handle a menu selection
  148. void FAR _export BCBtnMenuSelect(BYTE btnId, short itemId)
  149. {
  150.     // Clean up menu
  151.     DestroyMenu(hMenu);
  152.     hMenu = 0;
  153.  
  154.     switch (itemId) {
  155.  
  156.         case 1: PlayTrack(1); break;
  157.         case 2: PauseCD(); break;
  158.         case 3: StopCD(); break;
  159.         case 4: GoToTrack(TRUE); break;
  160.         case 5: GoToTrack(FALSE); break;
  161.         case 6: CDEject(); break;
  162.     }
  163.  
  164.     return;
  165. }
  166.  
  167.  
  168. /****************************************************************************
  169.  
  170.     FUNCTION  :  OpenCDDevice(HWND)
  171.  
  172.     PURPOSE   :  This function opens the device cdaudio and leaves it open.
  173.          The device could also be opened by assigning the string
  174.          "cdaudio" as follows.
  175.  
  176.          mciopen.lpstrDeviceType="cdaudio"
  177.  
  178.          Using this format you would only have to specify
  179.  
  180.          MCI_OPEN_TYPE for dwflags.
  181.  
  182.     COMMENTS  :
  183.  
  184.  
  185.     HISTORY   :
  186.  
  187. ****************************************************************************/
  188. static BOOL OpenCDDevice(BOOL bErr)
  189. {
  190.     MCI_OPEN_PARMS mciopen;
  191.     DWORD dwRes;
  192.  
  193.     if (wGlobalDeviceID == 0) {
  194.  
  195.         mciopen.wDeviceID = 0;
  196.         mciopen.lpstrDeviceType = (LPSTR)"cdaudio";
  197.  
  198.         dwRes = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE,
  199.                            (DWORD)(LPSTR)&mciopen);
  200.  
  201.         // If error
  202.         if (dwRes) {
  203.  
  204.             // if we care
  205.             if (bErr) {
  206.                 MessageBox(NULL, "Unable to open device.\n\nMake sure that an audio CD is loaded in your player!", "CD Error", MB_OK);
  207.             }
  208.  
  209.         } else {
  210.             wGlobalDeviceID = mciopen.wDeviceID;
  211.         }
  212.     }
  213.  
  214.     return (wGlobalDeviceID != 0);
  215. }
  216.  
  217. /****************************************************************************
  218.  
  219.     FUNCTION  :  CloseCDDevice(HWND,WORD)
  220.  
  221.     PURPOSE   :  This function closes a currently open cdaudio    device.
  222.  
  223.  
  224.     COMMENTS  :     To conserve system resources you should always close a
  225.          device when you are not using it.
  226.  
  227.     HISTORY   :
  228.  
  229. ****************************************************************************/
  230. static void CloseCDDevice(void)
  231. {
  232.     // Close the global device
  233.     ErrorProc(mciSendCommand(wGlobalDeviceID, MCI_CLOSE, 0, NULL));
  234.     wGlobalDeviceID = 0;
  235.     return;
  236. }
  237.  
  238.  
  239.  
  240. /****************************************************************************
  241.  
  242.     FUNCTION  :  PlayCD(HWND,WORD)
  243.  
  244.     PURPOSE   :  This function takes a currently open device ID and starts
  245.          the CD playing.
  246.  
  247.     COMMENTS  :  The format is set to TMSF to make sure that the when I
  248.          specify the starting position it is a valid position.
  249.          I am starting the CD at the beginning each time the
  250.          user presses play.  This could be just as easily the
  251.          currently paused position or someother position on
  252.          the CD.
  253.  
  254.  
  255.     HISTORY   :
  256.  
  257. ****************************************************************************/
  258. void PlayTrack(DWORD track)
  259. {
  260.     MCI_PLAY_PARMS mciplay;
  261.     MCI_SET_PARMS mciset;
  262.     DWORD dwRes = 0;
  263.  
  264.     if (OpenCDDevice(TRUE)) {
  265.  
  266.         //set time format to tmsf
  267.         mciset.dwTimeFormat = MCI_FORMAT_TMSF;
  268.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
  269.                            (DWORD)(LPSTR)&mciset);
  270.  
  271.         if (!dwRes) {
  272.  
  273.             // play the CD.
  274.             mciplay.dwFrom = MCI_MAKE_TMSF(track,0,0,0);
  275.             dwRes = mciSendCommand(wGlobalDeviceID, MCI_PLAY, MCI_FROM,
  276.                                (DWORD)(LPSTR)&mciplay);
  277.         }
  278.     }
  279.  
  280.     ErrorProc(dwRes);
  281.     return;
  282. }
  283.  
  284.  
  285. /****************************************************************************
  286.  
  287.     FUNCTION  :  StopCD(HWND,WORD)
  288.  
  289.     PURPOSE   :  This function stops a currently playing CD device.
  290.  
  291.  
  292.     COMMENTS  :
  293.  
  294.     HISTORY   :
  295.  
  296. ****************************************************************************/
  297. void StopCD(void)
  298. {
  299.     MCI_GENERIC_PARMS mcigeneric;
  300.  
  301.     if (OpenCDDevice(FALSE)) {
  302.  
  303.        ErrorProc(mciSendCommand(wGlobalDeviceID, MCI_STOP, 0,
  304.                            (DWORD)(LPSTR)&mcigeneric));
  305.  
  306.        CloseCDDevice();
  307.     }
  308.  
  309.      return;
  310. }
  311.  
  312. /****************************************************************************
  313.  
  314.     FUNCTION  :  PauseCD(HWND,WORD)
  315.  
  316.     PURPOSE   :  This function pauses a currently playing CD device.
  317.  
  318.  
  319.     COMMENTS  :  To implement pause you must first test to see whether the
  320.          CD is playing or stopped.  Yes it is stopped vs pause,
  321.          please note.  If the status is stopped you can restart the
  322.          CD from the currently paused position by playing.  If the
  323.          CD is playing then Pause the CD.
  324.  
  325.     HISTORY   :
  326.  
  327. ****************************************************************************/
  328. void PauseCD(void)
  329. {
  330.     MCI_GENERIC_PARMS mcigeneric;
  331.     MCI_STATUS_PARMS mcistatus;
  332.     MCI_PLAY_PARMS mciplay;
  333.     DWORD dwRes = 0;
  334.  
  335.     if (OpenCDDevice(FALSE)) {
  336.  
  337.         mcistatus.dwItem = MCI_STATUS_MODE;
  338.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  339.                            (DWORD)(LPSTR)&mcistatus);
  340.  
  341.         if (!dwRes) {
  342.  
  343.             // If play, then pause
  344.             if (mcistatus.dwReturn == MCI_MODE_PLAY) {
  345.                 dwRes = mciSendCommand(wGlobalDeviceID, MCI_PAUSE, 0,
  346.                                    (DWORD)(LPSTR)&mcigeneric);
  347.  
  348.                 // Failure? then stop
  349.                 if (dwRes) {
  350.                     StopCD();
  351.                     dwRes = 0;
  352.                 }
  353.  
  354.             // Resume if paused
  355.             } else if (mcistatus.dwReturn == MCI_MODE_PAUSE) {
  356.                 dwRes = mciSendCommand(wGlobalDeviceID, MCI_PLAY, 0,
  357.                                    (DWORD)(LPSTR)&mciplay);
  358.  
  359.             // Start from beginning
  360.             } else {
  361.                 PlayTrack(1);
  362.             }
  363.         }
  364.     }
  365.  
  366.     ErrorProc(dwRes);
  367.     return;
  368. }
  369.  
  370.  
  371. /****************************************************************************
  372.  
  373.     FUNCTION  :  GoToNextTrack(HWND,WORD)
  374.  
  375.     PURPOSE   :  This function goes to the next track on the CD.
  376.  
  377.  
  378.     COMMENTS  :  To implement GoToNextTrack you first need to find the
  379.          current position.  Then you need to find the total
  380.          number of tracks so that you can wrap when you get to
  381.          the end of the CD.  Then you increment the track value
  382.          by 1, if that number is greater than the number of tracks
  383.          reset to 1.  Pass this value to the SEEK command.
  384.  
  385.     HISTORY   :
  386.  
  387. ****************************************************************************/
  388. void GoToTrack(BOOL bNext)
  389. {
  390.     MCI_STATUS_PARMS mcistatus;
  391.     DWORD dwTrack;
  392.     DWORD dwRes = 0;
  393.  
  394.     if (OpenCDDevice(TRUE)) {
  395.  
  396.         mcistatus.dwItem = MCI_STATUS_CURRENT_TRACK;
  397.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  398.                            (DWORD)(LPSTR)&mcistatus);
  399.  
  400.         if (dwRes) {
  401.             ErrorProc(dwRes);
  402.             return;
  403.         }
  404.  
  405.         dwTrack = mcistatus.dwReturn;
  406.         mcistatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  407.         dwRes = mciSendCommand(wGlobalDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  408.                            (DWORD)(LPSTR)&mcistatus);
  409.  
  410.         if (dwRes) {
  411.             ErrorProc(dwRes);
  412.             return;
  413.         }
  414.  
  415.         // Next track
  416.         if (bNext) {
  417.  
  418.             if ((dwTrack + 1) > mcistatus.dwReturn) {
  419.                 dwTrack = 1;
  420.             } else {
  421.                 dwTrack++;
  422.             }
  423.  
  424.         // Previous track
  425.         } else {
  426.  
  427.             if (dwTrack == 1) {
  428.                 dwTrack = mcistatus.dwReturn;
  429.             } else {
  430.                 dwTrack--;
  431.             }
  432.         }
  433.  
  434.         // Play the track
  435.         PlayTrack(dwTrack);
  436.     }
  437.  
  438.     ErrorProc(dwRes);
  439.     return;
  440. }
  441.  
  442. /****************************************************************************
  443.  
  444.     FUNCTION  :  CDEject(HWND,WORD)
  445.  
  446.     PURPOSE   :  This function Ejects the CD from the physical CD-ROM drive.
  447.  
  448.  
  449.     COMMENTS  :
  450.  
  451.     HISTORY   :
  452.  
  453. ****************************************************************************/
  454. void CDEject(void)
  455. {
  456.     MCI_SET_PARMS mciset;
  457.  
  458.     if (OpenCDDevice(FALSE)) {
  459.  
  460.         ErrorProc(mciSendCommand(wGlobalDeviceID, MCI_SET, MCI_SET_DOOR_OPEN,
  461.                             (DWORD)(LPSTR)&mciset));
  462.     }
  463.  
  464.     return;
  465. }
  466.  
  467.  
  468. /****************************************************************************
  469.  
  470.     FUNCTION  :  ErrorProc(WORD)
  471.  
  472.     PURPOSE   :  ErrorProc calls mciGetErrorString to display an error
  473.          message returned by MCI.
  474.  
  475.     COMMENTS  :
  476.  
  477.     HISTORY   :
  478.  
  479. ****************************************************************************/
  480. void ErrorProc(DWORD dwResult)
  481. {
  482.     char buf[128];
  483.  
  484.     if (dwResult) {
  485.  
  486.         if (!mciGetErrorString(dwResult, buf, sizeof(buf)))
  487.             lstrcpy(buf, "Generic Error");
  488.  
  489.         MessageBox(NULL, buf, "ERROR", MB_OK);
  490.     }
  491.  
  492.     return;
  493. }
  494.